<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>单词小达人</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            font-family: 'Comic Sans MS', cursive;
            background: #f0f9ff;
            display: flex;
            flex-direction: column;
            
            min-height: 100vh;
            margin: 0;
            padding: 20px;
        }

        .score-board {
            display: flex;
            gap: 30px;
            margin: 0 0 30px 20px;
            font-size: 24px;
            color: #666;
        }

        .correct {
            color: #4CAF50;
        }

        .wrong {
            color: #f44336;
        }

        .question {
            text-align: center;
            width: 50%;
            background: #e7e4d7;
            padding: 15px 20px;
            border-radius: 20px;
            font-size: 36px;
            margin: 20px auto;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .word-bubbles {
            position: relative;
            width: 100%;
            min-height: 500px;
            margin-top: 30px;
        }

        .word-bubbles {
            overflow-y: auto;
            min-height: 80vh;
            max-height: 80vh;
        }

        .bubble {
            background: #4CAF50;
            color: white;
            border-radius: 50%;
            cursor: pointer;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            position: absolute;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            white-space: nowrap;
            padding: 10px;
            text-overflow: ellipsis;
            overflow: hidden;
        }

        .bubble:nth-child(2n) {
            background: #2196F3;
        }

        .bubble:nth-child(3n) {
            background: #FF9800;
        }

        .bubble:nth-child(4n) {
            background: #E91E63;
        }

        .bubble.wrong {
            animation: shake 0.5s;
            background: #ff4444;
        }

        @keyframes shake {

            0%,
            100% {
                transform: translateX(0);
            }

            25% {
                transform: translateX(10px);
            }

            75% {
                transform: translateX(-10px);
            }
        }

        .victory-effect {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 1000;
        }

        .import-btn {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #4CAF50;
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 25px;
            cursor: pointer;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
            transition: all 0.3s;
            z-index: 100;
        }

        .import-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
        }
    </style>
    <audio id="correctSound" src="success.wav"></audio>
    <audio id="wrongSound" src="error.wav"></audio>
    <audio id="victorySound" src="game-fanfare.mp3"></audio>
</head>

<body>
    <button class="import-btn" onclick="document.getElementById('fileInput').click()">📁 导入单词</button>
    <input type="file" id="fileInput" hidden accept=".xls,.xlsx">

    <div class="score-board">
        <div class="correct">正确：<span id="correctCount">0</span></div>
        <div class="wrong">错误：<span id="wrongCount">0</span></div>
    </div>

    <div class="question" id="chineseQuestion"></div>
    <div class="word-bubbles" id="wordContainer"></div>
    <div class="victory-effect" id="victoryEffect"></div>

    <script src="xlsx.full.min.js"></script>
    <script>
        // 彩带特效函数
        function createConfetti(container, count = 50) {
            // 添加动画关键帧样式
            if (!document.querySelector('#confetti-animations')) {
                const style = document.createElement('style');
                style.id = 'confetti-animations';
                style.textContent = `
                    @keyframes fall {
                        to {
                            top: 120%;
                            transform: rotate(${Math.random() * 720 + 360}deg);
                        }
                    }
                    @keyframes sway {
                        from {
                            transform: translateX(-20px) rotate(-45deg);
                        }
                        to {
                            transform: translateX(20px) rotate(45deg);
                        }
                    }
                `;
                document.head.appendChild(style);
            }

            // 创建彩带
            for (let i = 0; i < count; i++) {
                const confetti = document.createElement('div');
                confetti.style.position = 'absolute';
                confetti.style.width = Math.random() * 10 + 5 + 'px';
                confetti.style.height = Math.random() * 20 + 10 + 'px';
                confetti.style.backgroundColor = `hsl(${Math.random() * 360}, 100%, 50%)`;
                confetti.style.left = Math.random() * 100 + '%';
                confetti.style.top = '-20px';
                confetti.style.opacity = '0.8';
                confetti.style.transform = `rotate(${Math.random() * 360}deg)`;
                confetti.style.borderRadius = '4px';
                container.appendChild(confetti);

                const fallDuration = Math.random() * 2 + 2;
                const swayDuration = Math.random() * 2 + 2;
                confetti.style.animation = `
                    fall ${fallDuration}s linear forwards,
                    sway ${swayDuration}s ease-in-out infinite alternate
                `;
            }
        }

    
        const gameConfig = {
            // 布局配置
            layout: {
                basePadding: 100,
                rowStep: 0,
                sizeRange: [80, 140]
            },
            // 样式配置
            style: {
                bubbleColors: ['#4CAF50', '#2196F3', '#FF9800', '#E91E63'],
                wrongColor: '#ff4444',
                questionBgColor: '#FFD700'
            },
            // 动画配置
            animation: {
                shakeDuration: 0.5,
                victoryDuration: 2000,
                bubbleTransitionDuration: 0.3
            },
            // 音效配置
            sounds: {
                correct: 'success.wav',
                wrong: 'error.wav',
                victory: 'game-fanfare.mp3'
            },
            // 初始单词数据
            initialWords: [
                { en: "hello", zh: "你好" },
                { en: "apple", zh: "苹果" },
                { en: "dog", zh: "狗" },
                { en: "book", zh: "书" },
                { en: "car", zh: "车" },
                { en: "cat", zh: "猫" }
            ]
        };

        const layoutConfig = gameConfig.layout;
        let words = [...gameConfig.initialWords];
        let currentWord, correctCount = 0, wrongCount = 0;
        let answeredWords = [], remainingWords = [...words];


        // 修改createBubbleElement函数
        function createBubbleElement (word) {
            const bubble = document.createElement('div');
            bubble.className = 'bubble';
            bubble.textContent = word;

            // 使用配置的尺寸范围
            const size = Math.floor(Math.random() * (layoutConfig.sizeRange[1] - layoutConfig.sizeRange[0] + 1)) + layoutConfig.sizeRange[0];
            bubble.style.width = bubble.style.height = `${size}px`;

            // 字号计算逻辑
            const fontSize = Math.min(
                size * 0.35,  // 增加字体大小比例
                Math.max(28, size * 0.25)  // 调整最小和最大字体大小
            );
            bubble.style.fontSize = `${fontSize}px`;

            // 使用配置的颜色
            const colorIndex = Math.floor(Math.random() * gameConfig.style.bubbleColors.length);
            bubble.style.background = gameConfig.style.bubbleColors[colorIndex];

            positionBubble(bubble);
            return bubble;
        }

        // 修改positionBubble函数
        function positionBubble(bubble) {
            const container = document.getElementById('wordContainer');
            const containerRect = container.getBoundingClientRect();
            const bubbleSize = parseInt(bubble.style.width);
            
            // 计算网格大小
            const gridSize = Math.min(containerRect.width, containerRect.height) / 3; // 3x3网格
            const padding = gridSize * 0.1; // 添加10%的内边距
            
            // 获取当前已有的气泡数量
            const existingBubbles = container.children.length;
            
            // 计算当前气泡应该在的位置
            const row = Math.floor(existingBubbles / 3);
            const col = existingBubbles % 3;
            
            // 计算气泡的位置，居中对齐
            const left = (containerRect.width - gridSize * 3) / 2 + col * gridSize + padding;
            const top = row * gridSize + padding;
            
            // 设置气泡位置和大小
            const newBubbleSize = gridSize - padding * 2;
            bubble.style.width = bubble.style.height = `${newBubbleSize}px`;
            bubble.style.left = `${left}px`;
            bubble.style.top = `${top}px`;
            
            // 添加轻微的随机旋转效果
            const rotation = Math.random() * 6 - 3;
            bubble.style.transform = `rotate(${rotation}deg)`;
            
            return true;
        }

        function checkCollision (newBubble) {
            const allBubbles = document.getElementsByClassName('bubble');
            const newRect = newBubble.getBoundingClientRect();

            for (let bubble of allBubbles) {
                if (bubble === newBubble) continue;
                const existingRect = bubble.getBoundingClientRect();

                if (!(newRect.right < existingRect.left ||
                    newRect.left > existingRect.right ||
                    newRect.bottom < existingRect.top ||
                    newRect.top > existingRect.bottom)) return true;
            }
            return false;
        }

        function initGame () {
            if (remainingWords.length === 0) {
                document.getElementById('victorySound').play();
                const victoryEffect = document.getElementById('victoryEffect');
                victoryEffect.innerHTML = '';
                victoryEffect.style.display = 'block';
                createConfetti(victoryEffect, 100);
                setTimeout(() => {
                    victoryEffect.style.display = 'none';
                    victoryEffect.innerHTML = '';
                    alert(`🎉 胜利！\n正确: ${correctCount}次  错误: ${wrongCount}次 正确率：${parseInt((correctCount / (correctCount + wrongCount)) * 100)}%`);
                    resetGame();
                }, 3000);
                return;
            }

            currentWord = remainingWords[Math.floor(Math.random() * remainingWords.length)];
            document.getElementById('chineseQuestion').textContent = currentWord.zh;

            const wordContainer = document.getElementById('wordContainer');
            wordContainer.innerHTML = '';

            const wrongOptions = words
                .filter(w => w.en !== currentWord.en && !answeredWords.includes(w.en))
                .map(w => w.en)
                .sort(() => Math.random() - 0.5)
                .slice(0, 8);

            const allWords = wrongOptions.concat(currentWord.en).sort(() => Math.random() - 0.5);
            // 按配置的尺寸范围排序
            const sortedWords = allWords
                .map(word => ({
                    word,
                    size: Math.random() * (layoutConfig.sizeRange[1] - layoutConfig.sizeRange[0]) + layoutConfig.sizeRange[0]
                }))
                .sort((a, b) => b.size - a.size)
                .map(item => item.word);
            sortedWords.forEach(word => {
                const bubble = createBubbleElement(word);
                bubble.onclick = () => checkAnswer(word, bubble);
                wordContainer.appendChild(bubble);
            });

        }

        function checkAnswer (selectedWord, element) {
            if (selectedWord === currentWord.en) {
                answeredWords.push(currentWord.en);
                remainingWords = remainingWords.filter(w => w.en !== currentWord.en);
                document.getElementById('correctSound').play();
                correctCount++;
                element.style.transform = 'scale(0)';
                setTimeout(() => initGame(), gameConfig.animation.bubbleTransitionDuration * 1000);
            } else {
                document.getElementById('wrongSound').play();
                wrongCount++;
                element.classList.add('wrong');
                element.style.background = gameConfig.style.wrongColor;
                setTimeout(() => {
                    element.classList.remove('wrong');
                    element.style.background = '';
                }, gameConfig.animation.shakeDuration * 1000);
            }

            document.getElementById('correctCount').textContent = correctCount;
            document.getElementById('wrongCount').textContent = wrongCount;
        }

        function resetGame () {
            answeredWords = [];
            remainingWords = [...words];
            correctCount = wrongCount = 0;
            document.getElementById('correctCount').textContent = '0';
            document.getElementById('wrongCount').textContent = '0';
            initGame();
        }

        document.getElementById('fileInput').addEventListener('change', async e => {
            const file = e.target.files[0];
            if (!file) return;

            try {
                const data = await file.arrayBuffer();
                const workbook = XLSX.read(data);
                const jsonData = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);

                if (!jsonData[0]?.中文 || !jsonData[0]?.英文) {
                    alert('文件格式错误');
                    return;
                }

                const newWords = jsonData
                    .map(item => ({
                        zh: item.中文.trim(),
                        en: item.英文.trim().toLowerCase()
                    }))
                    .filter((item, index, self) =>
                        index === self.findIndex(t => t.zh === item.zh && t.en === item.en)
                    );

                words = [...newWords];
                remainingWords = [...newWords];
                alert(`导入成功 ${newWords.length} 个单词`);
                resetGame();
            } catch (error) {
                alert('文件读取失败: ' + error.message);
            }
        });

        initGame();
    </script>
</body>

</html>